<?php

  abstract class Parser extends Data
  {

      protected
              $formats = array(
                  'Genbank' => 'locus',
                  'Fasta' => '>',
                  'Nexus' => '#nexus',
                  'Phylip' => 'Phylip'
                      ),
              $parse_method = false;

      public function __construct()
      {
          if (!$method = $this->getParsingMethod())
          {
              throw new Exception('Unknown file format!');
          }
          else
          {
              $this->infile->rewind();
              $this->$method();
          }
      }

      public function getParsingMethod()
      {
          while ($line = $this->infile->fgets())
          {
              if ((int) $line)
              {
                  $this->parse_method = 'parsePhylip';
                  break;
              }
              
              foreach ($this->formats as $method => $tag)
              {
                  if (stripos($line, $tag) !== false)
                  {
                      $this->parse_method = 'parse' . $method;
                      break 2;
                  }
              }
          }
          return $this->parse_method;
      }

      public function parseFasta()
      {
          $i = count($this) - 1;

          while (!$this->infile->eof())
          {
              $line = trim($this->infile->fgets());
              // Gets taxa name
              if (preg_match('#^>(.+)#', $line, $match))
              {
                  $this[++$i] = new Seq();
                  $this[$i]->taxa = preg_replace('#\s+|\-#', '_', $match[1]);
                  continue;
              }
              // Gets chars and concatenate
              $this[$i]->chars .= $line;
          }
      }

      public function parseNexus()
      {
          $i = count($this) - 1;

          $matrix = false;

          $temp = array();

          while (!$this->infile->eof())
          {
              $line = trim($this->infile->fgets());
              if (strtolower($line) == 'matrix')
              {
                  $matrix = true;
              }
              else if ($matrix && preg_match('#^(.+)\s+(.+)#', $line, $match))
              {
                  $taxa = rtrim($match[1]);
                  if (!isset($temp[$taxa]))
                  {
                      $temp[$taxa] = ++$i;
                      $this[$temp[$taxa]] = new Seq();
                      $this[$temp[$taxa]]->taxa = preg_replace('#\s+|\-#', '_', $taxa);
                  }
                  $this[$temp[$taxa]]->chars .= $match[2];
              }
              else if ($matrix && $line == ';')
              {
                  break;
              }
          }
      }

      public function parseGenbank()
      {
          $origin = false;
          $i = count($this) - 1;

          while (!$this->infile->eof())
          {
              $line = rtrim($this->infile->fgets());

              // Gets Accession id
              if (preg_match('#^accession\s+(.+)#i', $line, $match))
              {
                  $accession = $match[1];
              }
              // Gets Organism name
              if (preg_match('#\/organism="(.+)"#', $line, $match))
              {
                  $this[++$i] = new Seq();
                  $this[$i]->taxa = $accession . '_' . preg_replace('#\s+#', '_', $match[1]);
              }

              // End characters
              if ($line == '//')
              {
                  $origin = false;
              }
              // Concatenate lines between origin and //, and remove spaces and numbers
              else if ($origin)
              {
                  $this[$i]->chars .= preg_replace('#[^a-z]#', '', $line);
              }
              // Start characters
              else if ($line == 'ORIGIN')
              {
                  $origin = true;
              }
          }
      }

      public function parsePhylip()
      {
          $i = -1;

          $block = false;

          while (!$this->infile->eof())
          {
              $line = trim($this->infile->fgets());

              // Gets the taxa name and firts line of charactes
              if (preg_match('#^(.+)\s+(.+)#', $line, $match) && !(int) $line)
              {
                  $this[++$i] = new Seq();
                  $this[$i]->taxa = $match[1];  // Taxa name
                  $this[$i]->chars = $match[2]; // Firts line of charactes
              }
              // New block of characters if the line is empty 
              else if (!$line)
              {
                  $block = true;
                  $i = -1;
              }
              // Concatenate chars
              else if ($block)
              {
                  $this[++$i]->chars .= $line;
              }
          }
      }

  }

?>
